﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DDD {

    /// <summary>
    /// キーフレーム構造体
    /// </summary>
    /// <remarks>
    /// キーフレームアニメーションで使用されるキーフレームを表します。
    /// １キーフレームは時刻と値のペアから構成されます。値は複数のコンポーネントからなる配列で管理されます。
    /// (実装の都合上スカラー値の時も長さ1の配列で管理しています)
    /// ユーザーが<dic>Keyframe</dic>型のオブジェクトを直接インスタンス化する事はできません。
    /// 必ずエンジン側が作成したものを戻り値で受け取ります。
    /// </remarks>
    /// <typeparam name="TValue">キーフレームが保存する値の型</typeparam>
    public struct Keyframe<TValue> where TValue : struct {

        /// <summary>
        /// 1要素のコンストラクター
        /// </summary>
        /// <param name="time">時刻(ローカル)</param>
        /// <param name="value">値</param>
        public Keyframe (int time, TValue value)
            : this () {
            this.Time = time;
            this.Value = new []{value};
        }

        /// <summary>
        /// 2要素のコンストラクター
        /// </summary>
        /// <param name="time">時刻(ローカル)</param>
        /// <param name="value1">値1</param>
        /// <param name="value2">値2</param>
        public Keyframe (int time, TValue value1, TValue value2)
            : this () {
            this.Time = time;
            this.Value = new []{value1, value2};
        }

        /// <summary>
        /// 3要素のコンストラクター
        /// </summary>
        /// <param name="time">時刻(ローカル)</param>
        /// <param name="value1">値1</param>
        /// <param name="value2">値2</param>
        /// <param name="value3">値3</param>
        public Keyframe (int time, TValue value1, TValue value2, TValue value3)
            : this () {
            this.Time = time;
            this.Value = new []{value1, value2, value3};
        }

        /// <summary>
        /// 4要素のコンストラクター
        /// </summary>
        /// <param name="time">時刻(ローカル)</param>
        /// <param name="value1">値1</param>
        /// <param name="value2">値2</param>
        /// <param name="value3">値3</param>
        /// <param name="value4">値4</param>
        public Keyframe (int time, TValue value1, TValue value2, TValue value3, TValue value4)
            : this () {
            this.Time = time;
            this.Value = new []{value1, value2, value3, value4};
        }

        /// <summary>
        /// コンストラクター
        /// </summary>
        /// <remarks>
        /// (実装メモ)ここfloatの間違えでは？　ローカル時間は原則floatだったはず。
        /// </remarks>
        /// <param name="time">ローカル時間</param>
        /// <param name="value">値</param>
        public Keyframe (int time, TValue[] value)
            : this () {
            this.Time = time;
            this.Value = (TValue[])value.Clone ();
        }


        /// <summary>
        /// 時刻(ローカル時間)
        /// </summary>
        public int Time { get; private set; }

        /// <summary>
        /// 値
        /// </summary>
        /// <remarks>
        /// コンポーネント数に応じて1～4の長さの配列が返ります。
        /// 通常とは異なり高速化のためにコピーではなく参照が返ります。
        /// </remarks>
        public TValue[] Value { get; private set; }

        /// <summary>
        /// コンポーネント数
        /// </summary>
        public int ComponentCount {
            get { return Value.Length; }
        }

        /// <summary>
        /// 現在のオブジェクトの状態を表す文字列を返します。
        /// </summary> 
        public override string ToString () {
            switch (ComponentCount) {
                case 1: return string.Format ("Keyframe : Time={0}, Value={1}", Time, Value[0]);
                case 2: return string.Format ("Keyframe : Time={0}, Value={1},{2}", Time, Value[0], Value[1]);
                case 3: return string.Format ("Keyframe : Time={0}, Value={1},{2},{3}", Time, Value[0], Value[1], Value[2]);
                case 4: return string.Format ("Keyframe : Time={0}, Value={1},{2},{3},{4}", Time, Value[0], Value[1], Value[2], Value[3]);
                default: return string.Format ("Keyframe : Error");
            }
        }
    }
}
